package com.atom.wyz.new_opengl.util;

import android.content.res.Resources;
import android.opengl.GLES30;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

public final class ShaderUtil {

    /**
     *
     */
    public static int loadShader(int shaderType, String res) {
        int shader = GLES30.glCreateShader(shaderType);
        if (shader != 0) {
            GLES30.glShaderSource(shader, res);
            GLES30.glCompileShader(shader);
            int[] compile = new int[1];
            GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compile, 0);
            if (compile[0] == 0) {
                Log.e("ES30_ERROR", "Could not compile shader " + shaderType + ":");
                Log.e("ES30_ERROR", GLES30.glGetShaderInfoLog(shader));
                GLES30.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }

    public static int createProgram(String vertexSource, String fragmentSource) {
        int vertexShader = loadShader(GLES30.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) return 0;
        int fragmentShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentSource);
        if (fragmentShader == 0) return 0;
        int i = GLES30.glCreateProgram();
        if (i == 0) return 0;
        GLES30.glAttachShader(i, vertexShader);
        checkGLError("glAttachShader > vertexShader");
        GLES30.glAttachShader(i, fragmentShader);
        checkGLError("glAttachShader > fragmentShader");
        GLES30.glLinkProgram(i);
        int[] link = new int[1];
        GLES30.glGetProgramiv(i, GLES30.GL_LINK_STATUS, link, 0);
        if (link[0] != GLES30.GL_TRUE) { //若链接失败则报错并删除程序
            Log.e("ES30_ERROR", "Could not link program: ");
            Log.e("ES30_ERROR", GLES30.glGetProgramInfoLog(i));
            GLES30.glDeleteProgram(i); //删除程序
            i = 0;
        }
        return i;
    }

    public static void checkGLError(String err) {
        int error; // error 变量
        while ((error = GLES30.glGetError()) != GLES30.GL_NO_ERROR) {
            //后台打印错误
            Log.e("ES30_ERROR", err + ": glError " + error);
            //抛出异常
            throw new RuntimeException(err + ": glError " + error);
        }
    }

    public static void checkGlError(String s) {
        checkGLError(s) ;
    }

    //从 sh 脚本中加载着色器内容的方法
    public static String loadFromAssetsFile(String fname, Resources r) {
        String result = null; //声明一个 String 类型的字符串变量
        try {
            InputStream in = r.getAssets().open(fname);//从 assets 文件夹中读取信息
            int ch = 0; //定义一个 int 型变量
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            while ((ch = in.read()) != -1) {
                baos.write(ch);
                //将获取的信息写入输出流中 //关闭输出流
            }
            byte[] buff = baos.toByteArray();
            baos.close();
            in.close();
            result = new String(buff, "UTF-8");
            result = result.replaceAll("\\r\\n", "\n");
        } catch (Exception e) {
            //转化为 UTF-8 编码 //捕获异常
            e.printStackTrace();
        }
        //打印异常 //返回结果
        return result;

    }

    public static int createProgram_TransformFeedback(String vertexSource,String fragmentSource)
    {
        int vertexShader=loadShader(GLES30.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) {
            return 0;
        }
        int pixelShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentSource);
        if (pixelShader == 0) {
            return 0;
        }
        int program = GLES30.glCreateProgram();
        if (program != 0)
        {
            GLES30.glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            GLES30.glAttachShader(program, pixelShader);
            checkGlError("glAttachShader");
            String feedbackVaryings[] = {"vPosition",};
            GLES30.glTransformFeedbackVaryings (
                    program,
                    feedbackVaryings,
                    GLES30.GL_INTERLEAVED_ATTRIBS
            );
            GLES30.glLinkProgram(program);

            int[] linkStatus = new int[1];
            GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, linkStatus, 0);
            if (linkStatus[0] != GLES30.GL_TRUE)
            {
                Log.e("ES20_ERROR", "Could not link program: ");
                Log.e("ES20_ERROR", GLES30.glGetProgramInfoLog(program));
                GLES30.glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }

}
